home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Pict Tricks / Batch CLUTLess / BatchCLUTs.c < prev    next >
Encoding:
Text File  |  1994-10-14  |  9.6 KB  |  359 lines  |  [TEXT/MMCC]

  1. //--------------------------------
  2. //--------------------------------
  3. //
  4. //    Code to strip the cluts from a folder of PICTs. See develop issue 20,
  5. //    Graphical Truffles column.
  6. //
  7.  
  8.  
  9. #include "MoreFilesExtras.h"
  10. #include "AppInterface.h"    // for AppendStr31 proto in utils.c
  11.  
  12. #define        kNumFSSpecs            2
  13. #define     kPICTHeaderSize        512 // the size of the header of a PICT file
  14.  
  15. // Prototypes
  16. OSErr            DoBatchClutStrip(void);
  17. OSErr            StripPICTFile(FSSpec *pictFileSpec, FSSpec *targetDirSpec);
  18. OSErr            SaveNewPict(PicHandle newPict, FSSpec *pictFileSpec,
  19.                                 FSSpec *targetDirSpec);
  20.  
  21. Boolean         CustomGet(FSSpec *fSpec);
  22. pascal void     StripClutProc(BitMap *src, 
  23.                                 Rect *srcR, Rect *dstR,
  24.                                 short mode, RgnHandle msk);
  25.                                 
  26. pascal    OSErr    GetTypedFilesInDir(short vRefNum,
  27.                             long dirID,
  28.                             StringPtr name,
  29.                             OSType    fileType,
  30.                             FSSpecPtr items,
  31.                             short reqItemCount,
  32.                             short *actItemCount,
  33.                             short *itemIndex);
  34.  
  35. // Globals
  36. CQDProcs    stripClutProcs; // Set of QDProcs that includes our custom bitsProc
  37. Boolean        gClutStripped;    // Set by the bitsProc to indicate if the clut was removed
  38.  
  39. extern WindowPtr     gWindow; // The one and only window (gag)
  40.  
  41. // Search recursively through all the files in a directory, strip the clut from 
  42. // every PICT file that has one
  43. OSErr DoBatchClutStrip(void)
  44. {
  45.     FSSpec        dirSpec, newDirSpec, fileSpecs[kNumFSSpecs];
  46.     Boolean        goodSelection;
  47.     short        actItemCount, itemIndex;
  48.     long        newDirID, i;
  49.     OSErr        err;
  50.     
  51.     // Select directory
  52.     goodSelection = CustomGet(&dirSpec);
  53.     if(goodSelection == false) // User canceled
  54.     {
  55.         SysBeep(10);
  56.         return noErr;
  57.     }
  58.     
  59.     // Create new directory for modified PICTs
  60.     newDirSpec = dirSpec;
  61.     AppendStr31(newDirSpec.name, "\p.stripped"); 
  62.     err = FSpDirCreate(&newDirSpec, smCurrentScript, &newDirID);
  63.     
  64.     // If the directory exists already, empty it
  65.     if(err == dupFNErr)
  66.     {
  67.         err = DeleteDirectoryContents(newDirSpec.vRefNum, newDirSpec.parID, newDirSpec.name);
  68.     }
  69.     
  70.     if(err != noErr)
  71.     {
  72.         SysBeep(10);
  73.         return err;
  74.     }
  75.     
  76.     // Initialize our bottlenecks to strip cluts
  77.     SetStdCProcs(&stripClutProcs);    // default procs
  78.     stripClutProcs.bitsProc = NewQDBitsProc(StripClutProc);
  79.     
  80.     // Show the window
  81.     ShowWindow(gWindow);
  82.     SetPort(gWindow);
  83.     
  84.     // Process all PICTs in directory
  85.     itemIndex = 1;
  86.     while(true)
  87.     {
  88.         // Get all the PICT files in the directory, up to kNumFSSpecs
  89.         GetTypedFilesInDir(dirSpec.vRefNum, dirSpec.parID, dirSpec.name, 'PICT',
  90.                     fileSpecs, kNumFSSpecs, &actItemCount, &itemIndex);
  91.         
  92.         // For each PICT            
  93.         for(i = 0; i < actItemCount; i++)
  94.         {
  95.             // Open PICT, strip clut, save new version
  96.             err = StripPICTFile(&fileSpecs[i], &newDirSpec);
  97.             if(err != noErr)
  98.             {
  99.                 // Error, let's clean up and return
  100.                 DeleteDirectory(newDirSpec.vRefNum, newDirSpec.parID, newDirSpec.name);
  101.                 return err;
  102.             }
  103.         }
  104.         
  105.         if(actItemCount < kNumFSSpecs) // we're done
  106.             break;
  107.     }
  108.     
  109.     // Hide window again
  110.     HideWindow(gWindow);
  111.     
  112.     // Beep
  113.     SysBeep(10);
  114.     
  115.     return noErr;
  116. }
  117.  
  118. OSErr StripPICTFile(FSSpec *pictFileSpec, FSSpec *targetDirSpec)
  119. {
  120.     OSErr        err = noErr;
  121.     PicHandle    oldPict, newPict;
  122.     Rect        pictRect;
  123.     short        refNum;
  124.     long        pictSize;
  125.     
  126.     // Open file
  127.     err = FSpOpenDF(pictFileSpec, fsRdPerm, &refNum);
  128.     if(err == noErr)
  129.     {
  130.         // Get the size of the data in the file
  131.         err = GetEOF(refNum, &pictSize);
  132.         if(err == noErr)
  133.         {
  134.             // subtract standard PICT header length
  135.             pictSize -= kPICTHeaderSize;
  136.             
  137.             // Try to allocate a handle big enough, first in temp mem, then app mem
  138.             oldPict = (PicHandle)TempNewHandle(pictSize, &err);
  139.             if(oldPict == nil || err != noErr) // Try for app mem
  140.             {
  141.                 oldPict = (PicHandle)NewHandle(pictSize);
  142.                 err = MemError();
  143.             }
  144.             
  145.             // If it worked, read in the pict
  146.             if(oldPict != nil)
  147.             {
  148.                 HLock((Handle)oldPict);
  149.                 
  150.                 // Set position to just after the file header
  151.                 err = SetFPos(refNum, fsFromStart, (long)kPICTHeaderSize);
  152.                 if(err == noErr)
  153.                 {
  154.                     err = FSRead(refNum, &pictSize, *oldPict);
  155.                     if(err == noErr)
  156.                     {
  157.                         // We have the PICT as a handle. Now just draw it
  158.                         // into a new picture
  159.                         pictRect = (**oldPict).picFrame;
  160.                         ClipRect(&pictRect);
  161.                         
  162.                         // Install custom bottlenecks and draw it, stripping clut
  163.                         qd.thePort->grafProcs = (QDProcsPtr)(&stripClutProcs);
  164.                         newPict = OpenPicture(&pictRect);
  165.                         DrawPicture(oldPict, &pictRect);
  166.                         ClosePicture();
  167.                         qd.thePort->grafProcs = nil;
  168.                         
  169.                         // Check for errors: QDError() doesn't seem to work,
  170.                         // but I noticed picSize was -1 when it died on one picture.
  171.                         // So what the hell.
  172.                         if(QDError() != noErr || (*newPict)->picSize != -1)
  173.                         {
  174.                             // Check global to see if a clut was stripped
  175.                             if(gClutStripped)
  176.                             {    
  177.                                 // Draw new picture in window
  178.                                 DrawPicture(newPict, &pictRect);
  179.                                 
  180.                                 // Save in a new file
  181.                                 err = SaveNewPict(newPict, pictFileSpec, targetDirSpec);
  182.                                 if(err != noErr)
  183.                                     DebugStr("\pFailed in SaveNewPict, but keep going");
  184.                             }
  185.                         }
  186.                         KillPicture(newPict);
  187.                     }
  188.                 }
  189.                 DisposHandle((Handle)oldPict);
  190.                 oldPict = nil;
  191.             }
  192.             else
  193.                 DebugStr("\pOut of Memory!");
  194.         }
  195.         FSClose(refNum);
  196.     }
  197.     return err;
  198. }
  199.  
  200.  
  201. // Save the given picture into a new file, like the old one but in the target directory
  202. OSErr SaveNewPict(PicHandle newPict, FSSpec *pictFileSpec, FSSpec *targetDirSpec)
  203. {
  204.     OSErr        err;
  205.     long        dirID, writeSize;
  206.     Boolean        isDir;
  207.     FSSpec        newPictSpec;
  208.     FInfo        info;
  209.     short        refNum;
  210.     Ptr            zeros;
  211.     
  212.     // First get the actual dirID of the destination directory
  213.     err = DirIDFromFSSpec(targetDirSpec, &dirID, &isDir);
  214.     if(err == noErr && isDir)
  215.     {
  216.         // Now make an FSSpec for the new file
  217.         err = FSMakeFSSpec(targetDirSpec->vRefNum, dirID, pictFileSpec->name,
  218.                             &newPictSpec);
  219.         
  220.         // Should get an fnfErr back, since the file doesn't exist. If not,
  221.         // do nothing
  222.         if(err == fnfErr)
  223.         {
  224.             // Get the FInfo for the old file so we can use the same type and creator
  225.             err = FSpGetFInfo(pictFileSpec, &info);
  226.             if(err == noErr)
  227.             {
  228.                 // Make the new file
  229.                 err = FSpCreate(&newPictSpec, info.fdCreator, info.fdType,
  230.                                     smCurrentScript);
  231.                 if(err == noErr)
  232.                 {
  233.                     // Open it
  234.                     err = FSpOpenDF(&newPictSpec, fsWrPerm, &refNum);
  235.                     if(err == noErr)
  236.                     {
  237.                         // Write out zeros for header bytes
  238.                         writeSize = kPICTHeaderSize;
  239.                         zeros = NewPtrClear(writeSize);
  240.                         if(zeros != nil)
  241.                         {
  242.                             err = FSWrite(refNum, &writeSize, zeros);
  243.                             DisposePtr(zeros);
  244.                             if(err == noErr)
  245.                             {
  246.                                 // Write out the pict
  247.                                 writeSize = GetHandleSize((Handle)newPict);
  248.                                 HLock((Handle)newPict); // needed?
  249.                                 err = FSWrite(refNum, &writeSize, *newPict);
  250.                             }
  251.                         }
  252.                         else err = memFullErr;
  253.                         FSClose(refNum);
  254.                     }
  255.                 }
  256.             }
  257.         }
  258.     }
  259.     return err;
  260. }
  261.  
  262.  
  263. // this is the custom bits proc that strips the color table
  264. pascal void StripClutProc(BitMap *src, 
  265.             Rect *srcR, Rect *dstR,
  266.             short mode, RgnHandle msk) 
  267. {
  268.     CTabHandle    saveCTH = nil;
  269.     
  270.     // Assume there's no clut to strip
  271.     gClutStripped = false;
  272.     
  273.     // If it's a PixMap...
  274.     if(src->rowBytes & 0x8000)
  275.     {
  276.         // ...and it's indexed...
  277.         if(((PixMap *)src)->pixelSize < 16)
  278.         {
  279.             // ...save color table handle and...
  280.             saveCTH = ((PixMapPtr) src)->pmTable;    
  281.             // ...replace it with nil instead.
  282.             ((PixMapPtr) src)->pmTable = nil;
  283.             // Tell the world what we've done
  284.             gClutStripped = true;
  285.         }
  286.     }
  287.     
  288.     // Let QuickDraw do the work.
  289.     StdBits(src, srcR, dstR, mode, msk);
  290.     
  291.     // Restore saved handle if necessary.
  292.     if(saveCTH != nil)
  293.         ((PixMapPtr) src)->pmTable = saveCTH;
  294. }
  295.  
  296. // Modified version of GetDirItems from MoreFiles
  297. pascal    OSErr    GetTypedFilesInDir(
  298.                             short vRefNum,
  299.                             long dirID,
  300.                             StringPtr name,
  301.                             OSType    fileType,     // Only return files of this type
  302.                             FSSpecPtr items,    // Array of FSSpecs to return items
  303.                             short reqItemCount,    // Number of items in array
  304.                             short *actItemCount,    // Actual number returned    
  305.                             short *itemIndex)    // start with 1, then use what's returned
  306. {
  307.     CInfoPBRec pb;
  308.     OSErr error = noErr;
  309.     long theDirID;
  310.     Boolean isDirectory;
  311.     FSSpec *endItemsArray = items + reqItemCount;
  312.  
  313.     /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
  314.     /* to this routine, I could rip out calls to DetermineVRefNum and GetDirID and this */
  315.     /* routine would be much faster because of the overhead of DetermineVRefNum and */
  316.     /* GetDirID and because GetDirID blows away the directory index hint the Macintosh */
  317.     /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
  318.     /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
  319.     /* to this routine. */
  320.     
  321.     /* get the real volume reference number */
  322.     error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum);
  323.     if ( error != noErr )
  324.         return ( error );
  325.     
  326.     /* and the real directory ID of this directory (and make sure it IS a directory) */
  327.     error = GetDirID(vRefNum, dirID, name, &theDirID, &isDirectory);
  328.     if ( error != noErr )
  329.         return ( error );
  330.     else if ( !isDirectory )
  331.         return ( dirNFErr );
  332.  
  333.  
  334.     *actItemCount = 0;
  335.     for ( ; (items < endItemsArray) && (error == noErr); )
  336.     {
  337.         pb.hFileInfo.ioNamePtr = (StringPtr) &items->name;
  338.         pb.hFileInfo.ioDirID = theDirID;
  339.         pb.hFileInfo.ioFDirIndex = *itemIndex;
  340.         error = PBGetCatInfoSync(&pb);
  341.         if ( error == noErr )
  342.         {
  343.             items->parID = pb.hFileInfo.ioFlParID;    /* return item's parID */
  344.             items->vRefNum = pb.hFileInfo.ioVRefNum;    /* return item's vRefNum */
  345.             ++*itemIndex;    /* prepare to get next item in directory */
  346.             
  347.             if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
  348.             {
  349.                 if(pb.hFileInfo.ioFlFndrInfo.fdType == fileType)
  350.                 {
  351.                     ++*actItemCount; /* keep this item */
  352.                     ++items; /* point to next item */
  353.                 }
  354.             }
  355.         }
  356.     }
  357.     return ( error );
  358. }
  359.